/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.infotypes;

import java.util.EnumMap;
import java.util.Vector;

import robocup.component.ControllerNumbers.TEAM;
import robocup.component.ControllerNumbers.VIEW_ANGLE;
import robocup.component.ControllerNumbers.VIEW_QUALITY;
import robocup.component.actions.Action;

/**
 * A SenseBodyInfo represents the information that can be "felt" by the
 * players. This is for instance his speed, or his stamina, and also the
 * executed actions (counter), which are important for detecting holes and
 * clashes.
 */
public class SenseBodyInfo extends Info implements Cloneable {

	/**
	 * The current view-quality of the player. This is one of HIGH or LOW.
	 */
	protected VIEW_QUALITY viewQuality;

	/**
	 * The current view-angle of the player. This is either NARROW, NORMAL 
	 * or WIDE.
	 */
	protected VIEW_ANGLE viewWidth;

	/**
	 * The current stamina of the agent.
	 */
	protected double stamina;

	/**
	 * The players current effort value.
	 */
	protected double effort;

	/**
	 * The players felt speed(-length).
	 */
	protected double speed;

	/**
	 * The players felt speed-direction.
	 */
	protected double speedDir;

	/**
	 * The neck-angle of the player. This is important for position
	 * determination, because all seen objects are relative to that 
	 * angle.
	 */
	protected double neckAngle;

	/**
	 * The number of cycles, the arm can't be redirected to 
	 * another point.
	 */
	protected int armMoveable;

	/**
	 * The number of cycles, the arm will stay at the point without refreshing
	 * the point-action.
	 */
	protected int armExpires;

	/**
	 * The distance to the point, the arm is directed to.
	 */
	protected double armDist;

	/**
	 * The direction to the point, the arm is directed to.
	 */
	protected double armDir;

	/**
	 * The team, to which an attention is set on.
	 */
	protected TEAM focusTeam;

	/**
	 * The number of the player, to whom the attention is set on (attentionto).
	 */
	protected int focusNumber;

	/**
	 * The number of cycles, the agent can't move due to tackling.
	 */
	protected int tackleExpires;

	/**
	 * The counter for all executed actions.
	 */
	protected EnumMap<Action.TYPE, Integer> counter = new EnumMap<Action.TYPE, Integer>(
			Action.TYPE.class);

	/**
	 * A list containing the actions that were missed.
	 */
	private Vector<Action> lastMissedActions;

	/**
	 * A list containing the actions sent last.
	 */
	private Vector<Action> lastSentActions;

	/**
	 * Constructor without any values: all data has to be set with
	 * setter-methods
	 */
	public SenseBodyInfo() {

		super(0);
		this.infoType = TYPE_SENSE;
	}

	/**
	 * A sense-body info, which is frequently received each cycle from the
	 * server, containing all agent-specific data
	 * 
	 * @param cycle -
	 *            the time, when the message was received
	 * @param viewQuality -
	 *            his view-quality (HIGH or LOW)
	 * @param viewAngle -
	 *            his view-angle (NARROW, NORMAL or WIDE)
	 * @param stamina -
	 *            the current stamina
	 * @param effort -
	 *            the current effort
	 * @param speed -
	 *            the current speed
	 * @param speedDir -
	 *            the direction of the speed
	 * @param neckAngle -
	 *            the neck-angle
	 * @param kickCount -
	 *            how often was a kick-action executed
	 * @param dashCount -
	 *            how often was a dash-action executed
	 * @param turnCount -
	 *            how often was a turn-action executed
	 * @param sayCount -
	 *            how often was a say-action executed
	 * @param turnNeckCount -
	 *            how often was a turnNeck-action executed
	 * @param catchCount -
	 *            how often was a catch-action executed
	 * @param moveCount -
	 *            how often was a move-action executed
	 * @param changeViewCount -
	 *            how often was a changeViewMode-action executed
	 * @param armMoveable -
	 *            is the arm movable (pointTo)
	 * @param armExpires -
	 *            how long does a current pointTo lasts at least
	 * @param armDist -
	 *            the distance to the target point, the agent is pointing to
	 * @param armDir -
	 *            the direction of the target point, the agent is pointing to
	 * @param focusTeam -
	 *            attention of which team (attentionTo)
	 * @param focusNumber -
	 *            attention on which player (unum - attentionTo)
	 * @param focusCount -
	 *            how often was an attentionTo executed
	 * @param tackleExpires -
	 *            how long does a current tackle-dead lasts at least
	 * @param tackleCount -
	 *            how often was a tackle-action executed
	 */
	public SenseBodyInfo(int cycle, VIEW_QUALITY viewQuality,
			VIEW_ANGLE viewAngle, double stamina, double effort, double speed,
			double speedDir, double neckAngle, int kickCount, int dashCount,
			int turnCount, int sayCount, int turnNeckCount, int catchCount,
			int moveCount, int changeViewCount, int armMoveable,
			int armExpires, double armDist, double armDir, TEAM focusTeam,
			int focusNumber, int focusCount, int tackleExpires, int tackleCount) {

		super(cycle);
		this.viewQuality = viewQuality;
		this.viewWidth = viewAngle;
		this.stamina = stamina;
		this.effort = effort;
		this.speed = speed;
		this.speedDir = speedDir;
		this.neckAngle = neckAngle;
		this.armMoveable = armMoveable;
		this.armExpires = armExpires;
		this.armDist = armDist;
		this.armDir = armDir;
		this.focusTeam = focusTeam;
		this.focusNumber = focusNumber;
		this.tackleExpires = tackleExpires;
		this.setCounter(Action.TYPE.ATTENTIONTO, focusCount);
		this.setCounter(Action.TYPE.TACKLE, tackleCount);
		this.setCounter(Action.TYPE.KICK, kickCount);
		this.setCounter(Action.TYPE.DASH, dashCount);
		this.setCounter(Action.TYPE.TURN, turnCount);
		this.setCounter(Action.TYPE.SAY, sayCount);
		this.setCounter(Action.TYPE.TURN_NECK, turnNeckCount);
		this.setCounter(Action.TYPE.CATCH_BALL, catchCount);
		this.setCounter(Action.TYPE.MOVE, moveCount);
		this.setCounter(Action.TYPE.CHANGE_VIEW_MODE, changeViewCount);
		this.cycle = cycle;

		this.infoType = TYPE_SENSE;
	}

	/**
	 * @return Returns the list of actions, which were sent in the
	 * last cycle.
	 */
	public Vector<Action> getLastSentActions() {

		return this.lastSentActions;
	}

	/**
	 * Sets a new list of actions to the info-obejct, which were
	 * sent last cycle.
	 * @param lastSentActions
	 */
	public void setLastSentActions(Vector<Action> lastSentActions) {

		this.lastSentActions = lastSentActions;
	}

	/**
	 * Sets a new list of actions, which were missed in the last cycle
	 * (hole).
	 * @param lastActions
	 */
	public void setLastMissedActions(Vector<Action> lastActions) {

		this.lastMissedActions = lastActions;
	}

	/**
	 * @return Returns the list of actions, which were missed in the
	 * last cycle.
	 */
	public Vector getLastMissedActions() {

		return this.lastMissedActions;
	}

	/**
	 * Returns teh amount of executed actions by type.
	 * @param type - the type of the action
	 * @return the amount of &lt;type&gt;-actions, which were successfully
	 *  executed.
	 */
	public int getCount(Action.TYPE type) {
		return this.counter.get(type).intValue();
	}

	/**
	 * Sets the amount of executed actions for the given type.
	 * @param type - the type of the action
	 * @param count - the counter for that action
	 */
	public void setCounter(Action.TYPE type, int count) {
		this.counter.put(type, Integer.valueOf(count));
	}

	/**
	 * @return Returns the cycle.
	 */
	@Override
	public int getCycle() {

		return this.cycle;
	}

	/**
	 * @return Returns the effort.
	 */
	public double getEffort() {

		return this.effort;
	}

	/**
	 * @return Returns the headAngle.
	 */
	public double getNeckAngle() {

		return this.neckAngle;
	}

	/**
	 * @return Returns the speed.
	 */
	public double getSpeed() {

		return this.speed;
	}

	/**
	 * @return Returns the speedDir.
	 */
	public double getSpeedDir() {

		return this.speedDir;
	}

	/**
	 * @return Returns the stamina.
	 */
	public double getStamina() {

		return this.stamina;
	}

	/**
	 * @return Returns the viewQuality.
	 */
	public VIEW_QUALITY getViewQuality() {

		return this.viewQuality;
	}

	/**
	 * @return Returns the viewWidth.
	 */
	public VIEW_ANGLE getViewWidth() {

		return this.viewWidth;
	}

	/**
	 * Sets a new view-quality for this info-object.
	 * @param viewQuality
	 */
	public void setViewQuality(VIEW_QUALITY viewQuality) {

		this.viewQuality = viewQuality;
	}

	/**
	 * Sets a new view-width for this info-object.
	 * @param viewWidth
	 */
	public void setViewWidth(VIEW_ANGLE viewWidth) {

		this.viewWidth = viewWidth;
	}

	/**
	 * Sets a new stamina value for this info-object.
	 * @param stamina
	 */
	public void setStamina(double stamina) {

		this.stamina = stamina;
	}

	/**
	 * Sets a new effort value for this info-object.
	 * @param effort
	 */
	public void setEffort(double effort) {

		this.effort = effort;
	}

	/**
	 * Sets a new speed value for this info-object.
	 * @param speed
	 */
	public void setSpeed(double speed) {

		this.speed = speed;
	}

	/**
	 * Sets a new speed-direction value for this info-object.
	 * @param speedDir
	 */
	public void setSpeedDir(double speedDir) {

		this.speedDir = speedDir;
	}

	/**
	 * Sets a new neck-angle value for this info-object.
	 * @param headAngle
	 */
	public void setNeckAngle(double headAngle) {

		this.neckAngle = headAngle;
	}

	/**
	 * Sets a new cycle value for this info-object.
	 * @param cycle
	 */
	@Override
	public synchronized void setCycle(int cycle) {

		this.cycle = cycle;
	}

	/**
	 * @return Returns the arm-direction.
	 */
	public double getArmDir() {

		return this.armDir;
	}

	/**
	 * Sets a new arm-direction value for this info-object.
	 * @param armDir
	 */
	public void setArmDir(double armDir) {

		this.armDir = armDir;
	}

	/**
	 * @return Returns the distance of the point, the arm is pointing to.
	 */
	public double getArmDist() {

		return this.armDist;
	}

	/**
	 * Sets a new arm pointing-distance value for this info-object.
	 * @param armDist
	 */
	public void setArmDist(double armDist) {

		this.armDist = armDist;
	}

	/**
	 * @return Returns the number of cycles, in which the arm expires in 
	 * pointing to the currect position, without refreshing the command.
	 */
	public int getArmExpires() {

		return this.armExpires;
	}

	/**
	 * Sets a new arm-expires value for this info-object.
	 * @param armExpires
	 */
	public void setArmExpires(int armExpires) {

		this.armExpires = armExpires;
	}

	/**
	 * @return Returns the number of cycles, in which the arm is movable
	 * again.
	 */
	public int getArmMoveable() {

		return this.armMoveable;
	}

	/**
	 * Sets a new arm-movable value for this info-object.
	 * @param armMoveable
	 */
	public void setArmMoveable(int armMoveable) {

		this.armMoveable = armMoveable;
	}

	/**
	 * @return Returns the number of cycles, in which the player can move again
	 * after tackling.
	 */
	public int getTackleExpires() {

		return this.tackleExpires;
	}

	/**
	 * Sets the number of cycles for this info-object, in which the 
	 * player can move again after tackling.
	 * @param tackleExpires
	 */
	public void setTackleExpires(int tackleExpires) {

		this.tackleExpires = tackleExpires;
	}

	/**
	 * @return Returns the number of the player, the attention is 
	 * set on.
	 */
	public int getFocusNumber() {

		return this.focusNumber;
	}

	/**
	 * Sets a new value for the number, the player is setting his attention to.
	 * @param focusNumber
	 */
	public void setFocusNumber(int focusNumber) {

		this.focusNumber = focusNumber;
	}

	/**
	 * @return Returns the TEAM (WE or OPPONENT), the attention is
	 * set on.
	 */
	public TEAM getFocusTeam() {

		return this.focusTeam;
	}

	/**
	 * Sets the team, to which the attention is set to.
	 * @param focusTeam
	 */
	public void setFocusTeam(TEAM focusTeam) {

		this.focusTeam = focusTeam;
	}

	/**
	 * @return Returns the sum of all action (DASH, KICK, TURN,
	 * CATCH_BALL, MOVE, TACKLE), which were executed up to now.
	 */
	public int getMainActionsCountSum() {

		return this.counter.get(Action.TYPE.KICK)
				+ this.counter.get(Action.TYPE.DASH)
				+ this.counter.get(Action.TYPE.TURN)
				+ this.counter.get(Action.TYPE.CATCH_BALL)
				+ this.counter.get(Action.TYPE.MOVE)
				+ this.counter.get(Action.TYPE.TACKLE);
	}

	/**
	 * @return Returns a debug-string for that info-object.
	 */
	public String toString() {
		String str = "";
		str += "\n DIRECTION: " + this.getArmDir();
		str += "\n DISTANCE : " + this.getArmDist();
		str += "\n EXPIRES  : " + this.getArmExpires();
		str += "\n MOVABLE  : " + this.getArmMoveable();
		return str;
	}

}
